﻿/*
 * Created by SharpDevelop.
 * User: Administrator
 * Date: 2016/4/21
 * Time: 16:45
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Net.Sockets;
using System.Reflection;
using SharpChannel.Rpc.Proxy;
using SharpChannel.Rpc.Serialization;
using TcpClient = SharpChannel.Core.TcpClient;

namespace SharpChannel.Rpc
{

    public class ClientProxyHandler : IProxyHandler
    {
        private readonly ISerializable serialization = FormatterManager.GetInstance().GetSerializable();

        private TcpClient client;

        private volatile bool connected;

        public bool TryConnect()
        {
            try
            {
                client = new TcpClient();
            }
            catch (Exception ex)
            {
               Util.LoggerHelper.GetLogger().Error("connect to server failed!", ex);
                client = null;
                connected = false;
                return false;
            }
            connected = true;
            return true;
        }

        public object Invoke(MethodInfo method, object[] args)
        {
#if DEBUG
            foreach (var item in args)
            {
                var type = item.GetType();
                if (type.IsPrimitive) continue;
                var attributes = type.GetCustomAttributes(typeof(SerializableAttribute), false);
                if (attributes.Length == 0)
                {
                    attributes = type.GetCustomAttributes(typeof(SerializableAttribute), true);
                    if (attributes.Length > 0)
                    {
                       Util.LoggerHelper.GetLogger().InfoFormat("class {0} doesn't have direct Serializable attribute.", method.Name);
                    }
                }
                if (attributes.Length == 0)
                {
                   Util.LoggerHelper.GetLogger().InfoFormat("class {0} doesn't have Serializable attribute at all.", method.Name);
                }
            }
#endif
            if (!connected) TryConnect();
            if (!connected)
            {
               Util.LoggerHelper.GetLogger().Error("connect to server failed!");
                return null;
            }
            var bytes = serialization.Serialize(new MethodInvokeInfo { MethodFullName = method.Name, Args = args });
            client.SendAndReiveMessage(bytes, out bytes);
            if (bytes == null)
            {
                throw new SocketException();
            }
            var obj = serialization.Deserialize(bytes);
            if (obj == null)
            {
                throw new SocketException();
            }
            var info = obj as MethodInvokeInfo;
            return info?.ReturnValue;
        }
    }
    /// <summary>
    /// Description of SharpChannelClient.
    /// </summary>
    public class SharpChannelClient<T> where T : class
    {
        private static T proxyObject ;

        public static T Instance()
        {
            return GetInstance();
        }

        public static T GetInstance()
        {
            return proxyObject ?? (proxyObject = new ProxyGenerator<T>(new ClientProxyHandler()).ProxyObject);
        }
    }
}
